using System;
using System.Collections.Generic;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;
using ScrewTurn.Wiki;
using System.Text.RegularExpressions;

namespace Stankovski.Wiki.FormattingPlus
{
	public class NumericHeaderFormatter : FormatterPlusBase
	{
		//private static Regex header = new Regex(@"<h(?<size>\d)[^>]*>\s*\#[^<]*</h\d>", RegexOptions.Compiled | RegexOptions.Singleline);
		private static Regex header = new Regex(@"^(?<pref>=+)(?<body>\s*[#]\s*[^=]+?)(?<suff>(?>=+))\n?", RegexOptions.Compiled | RegexOptions.Multiline);
		private static Regex anchorLinks = new Regex(@"(?<pref>\[[^#]+\#)(?<body>.+)(?<suff>\])", RegexOptions.Compiled | RegexOptions.Multiline);
		private static Regex anchors = new Regex("<a\\sid=\"([a-zA-Z_]+)_\\d+\"/?>", RegexOptions.Compiled | RegexOptions.Multiline);
		private static Regex anchors2 = new Regex("<a\\sid=\\\"[A-Z]{1,5}_([a-zA-Z_]+)_\\d+\\\"/?>", RegexOptions.Compiled | RegexOptions.Multiline);

		public override string Format(string raw, ContextInformation context, FormattingPhase phase)
		{
			if (phase == FormattingPhase.Phase1)
			{
				raw = formatHeaders(raw, context, phase);
				raw = formatAnchorLinks(raw, context, phase);
			}
			else if (phase == FormattingPhase.Phase2)
			{
				raw = formatAnchors(raw, context, phase);
			}
			
			return raw;
		}

		private string formatAnchors(string raw, ContextInformation context, FormattingPhase phase)
		{
			StringBuilder sb = new StringBuilder(raw);
			sb = new StringBuilder(anchors.Replace(sb.ToString(), "$&<a id=\"$1\"/>"));
			return anchors2.Replace(sb.ToString(), "$&<a id=\"_$1\"/>");
		}

		private string formatAnchorLinks(string raw, ContextInformation context, FormattingPhase phase)
		{
			StringBuilder sb = new StringBuilder(raw);
			List<int> noWikiBegin = new List<int>(), noWikiEnd = new List<int>();
			int end = 0;
			ComputeNoWiki(sb.ToString(), ref noWikiBegin, ref noWikiEnd);

			Match match = anchorLinks.Match(sb.ToString());
			try
			{
				while (match.Success)
				{
					if (!IsNoWikied(match.Index, noWikiBegin, noWikiEnd, out end))
					{
						sb.Remove(match.Groups["body"].Index, match.Groups["body"].Length);
						string newAnchor = ScrewTurn.Wiki.Formatter.BuildHAnchor(match.Groups["body"].Value);
						sb.Insert(match.Groups["body"].Index, newAnchor);
						end = match.Groups["body"].Index + newAnchor.Length;
					}
					ComputeNoWiki(sb.ToString(), ref noWikiBegin, ref noWikiEnd);
					match = header.Match(sb.ToString(), end);
				}
			}
			catch (Exception e)
			{

			}
			return sb.ToString();
		}

		private string formatHeaders(string raw, ContextInformation context, FormattingPhase phase)
		{
			int[] headers = new int[] { 0, 0, 0, 0, 0, 0 };

			StringBuilder sb = new StringBuilder(raw);
			List<int> noWikiBegin = new List<int>(), noWikiEnd = new List<int>();
			int end = 0;
			ComputeNoWiki(sb.ToString(), ref noWikiBegin, ref noWikiEnd);

			Match match = header.Match(sb.ToString());
			try
			{
				while (match.Success)
				{
					if (!IsNoWikied(match.Index, noWikiBegin, noWikiEnd, out end))
					{
						sb.Remove(match.Groups["body"].Index, match.Groups["body"].Length);

						headers[match.Groups["pref"].Value.Length - 2]++;
						for (int i = match.Groups["pref"].Value.Length - 1; i < headers.Length; i++)
						{
							headers[i] = 0;
						}
						sb.Insert(match.Groups["body"].Index, match.Groups["body"].Value.Replace("#", formatHeaderNumber(headers)));
					}
					ComputeNoWiki(sb.ToString(), ref noWikiBegin, ref noWikiEnd);
					match = header.Match(sb.ToString(), end);
				}
			}
			catch (Exception e)
			{

			}
			return sb.ToString();
		}

		private string formatHeaderNumber(int[] headers)
		{
			if (headers == null)
				return "";

			int length = headers.Length;
			for (int i = headers.Length - 1; i >= 0; i--)
			{
				if (headers[i] != 0)
				{
					length = i + 1;
					break;
				}
			}

			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < length; i++)
			{
				sb.Append(headers[i].ToString());
				if (i != length - 1)
					sb.Append(".");
			}
			return sb.ToString();
		}
	}
}
